package com.solidtrust.crawlers;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.apache.log4j.Logger;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.springframework.stereotype.Service;

import com.solidtrust.crawler.framework.BaseSitemap;
import com.solidtrust.crawler.model.PageSource;
import com.solidtrust.entity.Che168;
import com.solidtrust.entity.IScrapeEntity;
import com.solidtrust.util.DateUtil;
import com.solidtrust.util.ScrapeUtil;

@Service
public class Che168Sitemap extends BaseSitemap{

	private static final Logger log4j = Logger.getLogger(Che168Sitemap.class);
	private static final Date init = new Date(0);
	private Set<String> existingSet = new HashSet<>();
	public static final String[] COLORS = {
		"黑色","白色","银灰色",
		"深灰色","红色","蓝色",
		"绿色","黄色","香槟色",
		"紫色","橙色","棕色","其他"
	};
	
	@Override
	public void start() throws Exception{
		if(running == true){
			log4j.info(getSource() + " is running");
			return;
		}
		running = true;
		
		startDate = DateUtils.truncate(new Date(), Calendar.DATE);
		log4j.info("Start to crawl " + getSource() + " on " + startDate);
		
		log4j.info("[" + getSource() + "] start from last ID: " + commonDao.lastId(getEntityClass()));
		
		Document doc = parseURL(getStartUrl());
		crawlByBrandAndModel(doc, null);
		
		//save rest cars;
		persist();
		
		log4j.info("[" + getSource() + "]" + "Scrape " + news.size() + " cars");
		
		//touch old records
		touchOrRemove();
		
		log4j.info("Total requests: " + totalRequests);
		running = false;
	}
	
	/*
	 * 此方法较耗数据库资源
	 */
	protected void touchOrRemove(){
		commonDao.markDelete(startDate, getEntityClass());
	}
	
	@Override
	public void finish() {
		
	}
	
	@Override
	public String getStartUrl() {
		return "http://www.che168.com/china/#pvareaid=100939";
	}

	@Override
	public List<PageSource> getCitiesOrProvinces(Document doc) {
		return null;
	}

	@Override
	public List<PageSource> getBrands(Document doc, PageSource page) {
		List<PageSource> list = new ArrayList<>();
		Elements eles = doc.select(".menu-brand-pop a");
		for (int i = 0; i < eles.size(); i++) {
			PageSource c = new PageSource();
			c.setUrl(eles.get(i).attr("abs:href"));
			c.setName(eles.get(i).text());
			c.setId(c.getName());
			log4j.info(c);
			list.add(c);
		}
		return list;
	}

	@Override
	public List<PageSource> getModels(Document doc, PageSource page) {
		List<PageSource> list = new ArrayList<>();
		Elements eles = doc.select("#series .model-list a");
		for (int i = 0; i < eles.size(); i++) {
			PageSource c = new PageSource();
			c.setUrl(eles.get(i).attr("abs:href"));
			c.setName(eles.get(i).text());
			c.setId(c.getName());
			log4j.info(c);
			list.add(c);
		}
		return list;
	}

	@Override
	public String getSource() {
		return "che168";
	}

	@Override
	protected Class<? extends IScrapeEntity> getEntityClass() {
		return Che168.class;
	}

	@Override
	protected String getRowElementSelector() {
		return "#a2 li";
	}
	
	@Override
	protected IScrapeEntity eachItem(Element ele, String model, String brand) throws IOException {
		Element a = ele.child(0);
		String url = a.attr("href");
		int i = url.indexOf(".html");
		url = url.substring(0, i);
		i = url.lastIndexOf("/");
		String carId = url.substring(i + 1, url.length());
		String href = a.attr("abs:href");
		log4j.info("Collect car with ID " + carId + " from " + href);
		boolean notSold = ele.select(".sold").isEmpty();
		if(checkExist(carId, !notSold) == false){
			return null;
		}
		
		String title = ele.select(".info-con > h3").text();
		Che168 car = new Che168();
		car.setSourceId(carId);
		car.setAdTitle(title);//别克-君越 2013款 2.4L SIDI精英舒适型
		car.setAdUrl(href);
		car.setBuild(ScrapeUtil.getBuild(title));
		
		try {
			//buyDate
			String mileageInfo = ele.select(".info-con > p").text();
			int x = mileageInfo.indexOf("/");
			int y = mileageInfo.indexOf("／");
			//buy type
			car.setBuyerType(mileageInfo.substring(x + 1).trim());
			Date buyDate = DateUtil.string2Date3(mileageInfo.substring(y + 1, x));
			car.setBuyDate(buyDate);
			//mileage
			int mileage = (int)(Double.parseDouble(mileageInfo.substring(0, y).replace("万公里", "")) * 10000);
			car.setMileage(mileage);
		} catch (Exception e) {
			log4j.error(e.getMessage(), e);
		}
		
		try {
			String price = ele.select(".info-con > ins > em").text().replace("￥", "");
			car.setSoldPrice((int)(Double.parseDouble(price) * 10000));
		} catch (Exception e) {
			log4j.error(e.getMessage(), e);
		}
		
		try {
			String city = ele.select(".info-con > .location").text();
			car.setCity(city);
		} catch (Exception e) {
			log4j.error(e.getMessage(), e);
		}
		
		if(notSold){
			PageSource page = new PageSource();
			page.setName(carId);
			page.setUrl(href);
			try {
				eachDetailPage(page, car);
			} catch (Exception e) {
				log4j.error(e.getMessage(), e);
			}
		}else{
			car.setRemovedDate(init);
		}
		
		return car;
	}
	
	private void eachDetailPage(PageSource page, Che168 car)throws Exception{
		Document doc = parseURL(page.getUrl());
		
		try {
			//owner
			Element owner = doc.select(".merchants-info").first();
			if(owner != null){
				car.setSellerName(owner.child(0).childNode(2).toString());
				car.setSellerAddress(owner.select(".address").text());
			}else{
				if(doc.select(".car-title .hao-logo1").size() > 0){
					car.setSellerName("汽车之家");
				}
			}
		} catch (Exception e) {
			log4j.error(e.getMessage(), e);
		}
		
		try {
			String s = doc.select(".car-info .activity").text();
			if(StringUtils.isNotBlank(s)){
				int i = s.indexOf("天");
				if(i > -1){
					int days = Integer.parseInt(s.substring(0, i));
					car.setAdDate(DateUtils.addDays(startDate, - days));
				}else{
					car.setAdDate(startDate);
				}
			}
		} catch (Exception e) {
			log4j.error(e.getMessage(), e);
		}
		
		try {
			String emission = doc.select(".details li span").get(2).text();
			car.setEmission(emission);
		} catch (Exception e) {
			log4j.error(e.getMessage(), e);
		}
		
		try {
			//telephone
			Element phoneEle = doc.select(".tab01-iphone").first();
			if(!phoneEle.children().isEmpty()){
				String phone = phoneEle.childNode(1).toString();
				car.setPhone(phone);
			}
		} catch (Exception e) {
			log4j.error(e.getMessage(), e);
		}
		
			Elements basicInfo1 = doc.select("#anchor01 li");
			for (Element bi : basicInfo1) {
				//basic info
				String text = bi.text();
				String value = null;
				if((value = ScrapeUtil.getString(text, "年检到期")) != null){
					try {
						car.setInspectionDate(DateUtil.parseMonth(value));
					} catch (Exception e) {}
				}
				else if((value = ScrapeUtil.getString(text, "保险到期")) != null){
					try {
						car.setInsuranceDate(DateUtil.parseMonth(value));
					} catch (Exception e) {}
				}
				else if((value = ScrapeUtil.getString(text, "交强险到期")) != null){
					try {
						car.setInsuranceDate(DateUtil.parseMonth(value));
					} catch (Exception e) {}
				}
				else if((value = ScrapeUtil.getString(text, "过户次数")) != null){
					try {
						car.setSoldTimes(Integer.parseInt(value.replace("次", "")));
					} catch (Exception e) {}
				}
				else if((value = ScrapeUtil.getString(text, "排放标准")) != null){
					car.setEmission(value);
				}
			}
		
		if(StringUtils.isEmpty(car.getEmission())){
			car.setEmission(doc.select("#paiFangVal").val());
		}
		
		try {
			//basic info
			Elements basicInfo2 = doc.select("#anchor02 li");
			for (Element bi : basicInfo2) {
				String text = bi.text();
				String value = null;
				if((value = ScrapeUtil.getString(text, "颜　　色")) != null){
					car.setColor(value);
				}
				else if((value = ScrapeUtil.getString(text, "车辆级别")) != null){
					car.setType(value);
				}
				else if((value = ScrapeUtil.getString(text, "发 动 机")) != null){
					car.setMotor(value);
				}
			}
		} catch (Exception e) {
			log4j.error(e.getMessage(), e);
		}
		
	}

	@Override
	protected PageSource getNextPage(Document doc) {
		Element next = doc.select("a.page-item-next").last();
		if(next != null){
			PageSource nextPage = new PageSource();
			nextPage.setUrl(next.attr("abs:href"));
			return nextPage;
		}
		return null;
	}
	
	protected void toTouch(String carId){
		existingSet.add(carId);
		if(existingSet.size() == 100){
			commonDao.touchBySourceId(existingSet, startDate, getEntityClass());
			existingSet.clear();
		}
	}
	
	protected boolean checkExist(String carId, boolean markSold){
		//check new
		if(news.contains(carId)){
			log4j.info(carId + " exists minutes ago");
			return false;
		}
		
		//check unsold
		if(commonDao.unSold(carId, getEntityClass())){
			log4j.info(carId + " exists in DB");
			if(markSold == true){
				log4j.info("but marked sold");
			}else{
				toTouch(carId);
			}
			return false;
		}
		//check sold
		if(commonDao.hasSold(carId, getEntityClass())){
			log4j.info(carId + " has been sold last time");
			return false;
		}
		
		news.add(carId);
		return true;
	}

	
	public static void main(String[] args) throws Exception {
		Che168Sitemap s = new Che168Sitemap();
		PageSource p = new PageSource();
		p.setUrl("http://www.che168.com/authentication/4856607.html?pvareaid=101115");
		Document doc = s.parseURL(p.getUrl());
		System.out.println(doc.baseUri());
	}

}


